package api_error

import (
	"app-box/config"
	"app-box/tools/caller"
	"fmt"
	"strings"
)

type ApiErrorType interface {
	error
	GetCode() int
	GetMessage() string
	GetOriginError() error
	GetDebugInfo() string
	GetIsInternalError() bool
}

type ApiError struct {
	Code            int    // 错误码
	Message         string // 错误信息
	OriginError     error  // 原始错误，可以为空
	DebugInfo       string // 调试信息，产生错误的文件位置
	IsInternalError bool   // 决定这个错误是直接返回给前端还是只给前端提示 500 服务器内部错误
	skipLevel       int
}

func (apierr ApiError) GetCode() int {
	return apierr.Code
}

func (apierr ApiError) GetMessage() string {
	return apierr.Message
}
func (apierr ApiError) GetOriginError() error {
	return apierr.OriginError
}
func (apierr ApiError) GetDebugInfo() string {
	return apierr.DebugInfo
}
func (apierr ApiError) GetIsInternalError() bool {
	return apierr.IsInternalError
}

func (apierr ApiError) Error() string {
	return apierr.Message
}

type option func(*ApiError)

func code(code int) option {
	return func(ae *ApiError) {
		ae.Code = code
	}
}

func message(messages ...string) option {
	return func(ae *ApiError) {
		ae.Message = strings.Join(messages, " ")
	}
}

func messagef(format string, a ...interface{}) option {
	return func(ae *ApiError) {
		ae.Message = fmt.Sprintf(format, a...)
	}
}

func originError(err error) option {
	return func(ae *ApiError) {
		ae.OriginError = err
	}
}

func internalError() option {
	return func(ae *ApiError) {
		ae.IsInternalError = true
	}
}

func skipCallerLevel(level int) option {
	return func(ae *ApiError) {
		ae.skipLevel = level
	}
}

func new(options ...option) ApiErrorType {
	var newError = ApiError{}
	newError.IsInternalError = false
	for _, item := range options {
		item(&newError)
	}
	newError.DebugInfo = caller.GetCallerInfoStrWithBasePath(config.BasePath, 3+newError.skipLevel)
	return newError
}
